<?php

declare(strict_types=1);

namespace app\common\traits;

/**
 * Dao层公共方法（数据访问层 - 操作层）
 * @author:kaige
 * @update:2022-06-12
 * @copyright ©2022 泉州市盛筑信息科技有限公司 版权所有
 * @explain model层必须 存在允许字段 allowField，必须指定 model 指向本model，必须声明主键pk。修改此文档时必须在团队说明原由
 */
trait DaoTrait
{
  /**
   * 删除数组里的元素 -- 一般情况放在输出数据前调用。
   * @param array $data 
   * @param int $type 1为一维数组，2=2维数组 当前只支持到2维，如有需要再扩展
   */
  public function delArrayField($data, $type = 1)
  {
    switch ($type) {
      case 1:
        if (!empty($this->hideField)) {
          foreach ($this->hideField as $v) {
            if (isset($data[$v])) {
              unset($data[$v]);
            }
          }
        }
        break;
      case 2:
        if (!empty($this->hideField)) {
          foreach ($this->hideField as $v) {
            foreach ($data as $key => $val) {
              if (isset($val[$v])) {
                unset($data[$key][$v]);
              }
            }
          }
        }
        break;
    }
    return $data;
  }

  /**
   * 根据主键获取信息
   * @param int|string $id 主键
   * @param array|bool $where 查询条件
   * @param array $field 需要显示的字段
   * @return mixed 返回实例对象 
   */
  public function getInfoById($id = 0, $where = true, $field = [])
  {
    $ifield = empty($field) ? $this->allowField : $field;
    $data = $this->model->field($ifield)->where($this->pk, $id)->where($where)->find();
    return $this->delArrayField($data, 1);
  }

  /**
   * 根据查询条件获取信息 与 getInfoById 区别 此方法不需要主键
   * @param array|bool $where 查询条件 条件中需保证记录只有一条
   * @param array $field 需要显示的字段
   * @return mixed 返回实例对象
   */
  public function getInfoByWhere($where = true, $field = [])
  {
    $ifield = empty($field) ? $this->allowField : $field;
    $data = $this->model->field($ifield)->where($where)->find();
    return $this->delArrayField($data, 1);
  }

  /**
   * 根据查询条件获取信息 与 getInfoById 区别 此方法不需要主键
   * @param array|bool $where 查询条件 条件中需保证记录只有一条
   * @param array $field 需要显示的字段
   * @return mixed 返回实例对象
   */
  public function getInfoByCacheWhere($where = true, $field = [])
  {
    $ifield = empty($field) ? $this->allowField : $field;
    $data = $this->model->field($ifield)->where($where)->cache(true)->find();
    return $this->delArrayField($data, 1);
  }

  /**
   * 根据查询条件获取信息 返回是对象且不过滤隐藏字段
   * @param array|bool $where 查询条件 条件中需保证记录只有一条
   * @param array $field 需要显示的字段
   * @return mixed 返回实例对象
   */
  public function getInfoByWhereObj($where = true, $field = [])
  {
    $ifield = empty($field) ? $this->allowField : $field;
    return $this->model->field($ifield)->where($where)->find();
  }

  /**
   * 根据默认查询字段查询
   * @param mixed $name 每个表除了主键有个默认的字段，例：name
   * @param array|bool $where 查询条件
   * @return mixed 返回实例对象
   */
  public function getInfoByName($name = '', $where = true, $field = [])
  {
    $ifield = empty($field) ? $this->allowField : $field;
    $data = $this->model->field($ifield)->where($this->name, $name)->where($where)->find();
    return $this->delArrayField($data, 1);
  }

  /**
   * 查询满足条件的数量
   * @param array|bool $where 查询条件
   * @return int 返回数量，无数据返回0
   */
  public function getTotal($where = true)
  {
    return $this->model->where($where)->count();
  }

  /**
   * 分页查询
   * @param int $page 当前页
   * @param int $limit 每页数量 默认 20
   * @param array|bool $where 查询条件
   * @param array $order 排序规则
   * @param array $field 显示的字段
   * @return array 返回数组
   */
  public function getLists($page = 1, $limit = 20, $where = true, $order = ['id' => 'asc'], $field = [])
  {
    $ifield = empty($field) ? $this->allowField : $field;
    $data = $this->model->field($ifield)->where($where)->order($order)->page($page, $limit)->select()->toArray();
    $data = $this->delArrayField($data, 2);
    $count = $this->getTotal($where);
    return ['page' => $page, 'limit' => $limit, 'count' => $count, 'data' => $data];
  }

  /**
   * 查询所有数据
   * @param array|bool $where 查询条件
   * @param array|bool $order 排序
   * @return array
   */
  public function getListAll($where = true, $order = false, $field = [])
  {
    $ifield = empty($field) ? $this->allowField : $field;
    if ($order === false) {
      $data = $this->model->field($ifield)->where($where)->select()->toArray();
    } else {
      $data = $this->model->field($ifield)->where($where)->order($order)->select()->toArray();
    }
    return $this->delArrayField($data, 2);
  }

  /**
   * 新增
   * @param array $data
   * @return mixed 返回实例对象或false
   */
  public function add($data)
  {
    $result = $this->model->create($data);
    if ($result) {
      return $result;
    } else {
      return  false;
    }
  }

  /**
   * 更新数据
   * @param int $id
   * @param array $data
   * @return mixed
   */
  public function update($id, $data)
  {
    $result = $this->model->find($id);
    if ($result) {
      return $result->save($data);
    } else {
      return false;
    }
  }

  /**
   * 更新数据按条件
   * @param array $where
   * @param array $data
   * @return mixed
   */
  public function updateByWhere($where, $data)
  {
    return $this->model->where($where)->update($data);
  }

  /**
   * 根据主键删除单条数据
   * @param int $id
   * @return bool
   */
  public function delete($id)
  {
    $result = $this->model->find($id);
    if ($result) {
      return $result->delete() > 0;
    } else {
      return false;
    }
  }

  /**
   * 根据条件删除数据
   * @param array $where
   * @return bool
   */
  public function deleteByWhere($where)
  {
    $result = $this->model->where($where)->column('id');
    if ($result) {
      return $this->model->destroy($result) > 0;
    } else {
      return false;
    }
  }

  /**
   * 批量删除 $ids不能=0
   * @param array|string $ids  string:'1,2,...'
   * @return bool
   */
  public function multiDelete($ids)
  {
    $result = $this->model->destroy($ids);
    if ($result) {
      return $result;
    } else {
      return false;
    }
  }

  /**
   * 删除数据，支持批量删除
   * @param string $id 
   * @return array
   */
  public function _del($id)
  {
    if (!empty($id)) {
      //批量删除
      $ids = explode(',', $id);
      $info = $this->model->find($ids[0])->toArray();
      if (in_array("delete_time", $info, true)) {
        //如果delete_time存在，软删除
        $this->model->whereIn('id', $ids)->useSoftDelete('delete_time', time())->delete();
        return _ok(1027);
      }
      //否则根据主键物理删除
      $this->model->destroy($ids);
      return _ok(1025);
    }
    return _err(1026);
  }

  /**
   * 单字段值更新-允许INT字段，必须在model设置允许的字段 uaField=[...]
   * @param int $id
   * @param string $field
   * @param mixed $val
   * @return bool
   */
  public function updateField($id = 0, $field = '', $val)
  {
    if ($id > 0) {
      //检查是否允许字段(每个表里允许更改的字段有限)
      $array = $this->uaField;
      if (in_array($field, $array)) {
        $info = $this->model->find($id);
        if ($info) {
          $data = [];
          $data[$field] = $val;
          if ($this->model->where('id', $id)->update($data) > 0) return true;
        }
      }
    }
    return false;
  }

  /**
   * 根据主键获取单字段值
   * @param int $id 主键
   * @param string $field 字段名
   * @return mixed
   */
  public function oneField($id = 0, $field = '')
  {
    $info = $this->model->find($id);
    if ($info) {
      $info = $info->toArray();
      if (isset($info[$field])) {
        return $info[$field];
      }
    }
    return '';
  }

  //--------------------------含关联取列表（开始）--------------------------

  /**
   * 获取列表
   * @param array $data 查询条件
   * @param bool $isPage 是否分页 默认分页
   * @return mixed
   */
  public function getList($data = [], $isPage = true)
  {
    $field = (isset($data['field']) && !empty($data['field'])) ? $data['field'] : $this->allowField;
    $where = (isset($data['where']) && !empty($data['where'])) ? $data['where'] : false;
    $whereOr = (isset($data['whereOr']) && !empty($data['whereOr'])) ? $data['whereOr'] : false;
    $order = (isset($data['order']) && !empty($data['order'])) ? $data['order'] : false;
    if ($whereOr) {
      if ($isPage) {
        $list = $this->model->where($where)->whereOr($whereOr)->order($order)->limit($data['begin'], $data['limit'])->field($field)->select();
      } else {
        $list = $this->model->where($where)->whereOr($whereOr)->order($order)->field($field)->select();
      }
    } else {
      if ($isPage) {
        $list = $this->model->where($where)->order($order)->limit($data['begin'], $data['limit'])->field($field)->select();
      } else {
        $list = $this->model->where($where)->order($order)->field($field)->select();
      }
    }
    return $list;
  }

  /**
   * 获取列表（关联）必须存在with的方法
   * @param array $data 查询条件
   * @param bool $isPage 是否分页
   * @return mixed
   */
  public function getListWith($data = [], $isPage = true)
  {
    $field = (isset($data['field']) && !empty($data['field'])) ? $data['field'] : $this->allowField;
    $where = (isset($data['where']) && !empty($data['where'])) ? $data['where'] : false;
    $whereOr = (isset($data['whereOr']) && !empty($data['whereOr'])) ? $data['whereOr'] : false;
    $order = (isset($data['order']) && !empty($data['order'])) ? $data['order'] : false;
    if ($whereOr) {
      if ($isPage) {
        $list = $this->model->with($data['with'])->where($where)->whereOr($whereOr)->order($order)->limit($data['begin'], $data['limit'])->field($field)->select();
      } else {
        $list = $this->model->with($data['with'])->where($where)->whereOr($whereOr)->order($order)->field($field)->select();
      }
    } else {
      if ($isPage) {
        $list = $this->model->with($data['with'])->where($where)->order($order)->limit($data['begin'], $data['limit'])->field($field)->select();
      } else {
        $list = $this->model->with($data['with'])->where($where)->order($order)->field($field)->select();
      }
    }
    return $list;
  }

  /**
   * 查询数量
   * @param array $data 查询条件 $data['where']，$data['whereOr']
   * @return int
   */
  public function getCount($data)
  {
    if (isset($data['whereOr']) && !empty($data['whereOr'])) {
      return $this->model->where($data['where'])->whereOr($data['whereOr'])->count();
    }
    return $this->model->where($data['where'])->count();
  }

  /**
   * 查询数量-关联
   * @param array $data 查询条件 $data['where']，$data['whereOr']
   * @return int
   */
  public function getCountWith($data)
  {
    if (isset($data['whereOr']) && !empty($data['whereOr'])) {
      return $this->model->with($data['with'])->where($data['where'])->whereOr($data['whereOr'])->count();
    }
    return $this->model->with($data['with'])->where($data['where'])->count();
  }
  //--------------------------关联取列表（结束）----------------------------------------

  /**
   * 查询已经软删除的列表，无关联
   * @param array $data 查询条件
   * @param bool $isPage 是否分页 默认分页
   * @return mixed
   */
  public function getRecycleList($data = [], $isPage = true)
  {
    if ($isPage) {
      if (isset($data['limit'])) {
        $limit = $data['limit'];
      } else {
        $limit = 20;
      }
      $data['limit'] = (int)$limit;
      if (isset($data['page'])) {
        $page = $data['page'];
      } else {
        $page = 1;
      }
      $begin = intval(($page - 1) * $limit);
      $data['begin'] = (int)$begin;
    }
    $field = (isset($data['field']) && !empty($data['field'])) ? $data['field'] : $this->allowField;
    $where = (isset($data['where']) && !empty($data['where'])) ? $data['where'] : false;
    $whereOr = (isset($data['whereOr']) && !empty($data['whereOr'])) ? $data['whereOr'] : false;
    $order = (isset($data['order']) && !empty($data['order'])) ? $data['order'] : false;
    if ($whereOr) {
      if ($isPage) {
        $list = $this->model->onlyTrashed()->where($where)->whereOr($whereOr)->order($order)->field($field)->limit($data['begin'], $data['limit'])->select();
      } else {
        $list = $this->model->onlyTrashed()->where($where)->whereOr($whereOr)->order($order)->field($field)->select();
      }
    } else {
      if ($isPage) {
        $list = $this->model->onlyTrashed()->where($where)->order($order)->field($field)->limit($data['begin'], $data['limit'])->select();
      } else {
        $list = $this->model->onlyTrashed()->where($where)->order($order)->field($field)->select();
      }
    }
    return $this->delArrayField($list, 2);
  }

  /**
   * 查询数量--已经软删除的列表，无关联
   * @param array $data 查询条件 $data['where'],$data['whereOr']
   * @return int
   */
  public function getRecycleCount($data)
  {
    if (isset($data['whereOr']) && !empty($data['whereOr'])) {
      return $this->model->onlyTrashed()->where($data['where'])->whereOr($data['whereOr'])->count();
    }
    return $this->model->onlyTrashed()->where($data['where'])->count();
  }

  //--------------------------关联流程取列表（开始）--------------------------
  /**
   * 获取列表（关联）必须存在with  flowbill的方法
   * @param array $data 查询条件
   * @return mixed
   */
  public function getListFlow($data = [])
  {
    $mainWhere = (isset($data['mainWhere']) && !empty($data['mainWhere'])) ? $data['mainWhere'] : [];
    $sideWhere = (isset($data['sideWhere']) && !empty($data['sideWhere'])) ? $data['sideWhere'] : [];
    $whereOr = (isset($data['sideWhereOr']) && !empty($data['sideWhereOr'])) ? $data['sideWhereOr'] : [];
    $order = (isset($data['sideOrder']) && !empty($data['sideOrder'])) ? $data['sideOrder'] : false;
    if (empty($mainWhere)) {
      $hwhere = [];
    } else {
      $hwhere = $mainWhere;
    }
    if (isset($data['alias'])) {
      $list = $this->model->alias($data['alias'])
        ->hasWhere('flowbill', $hwhere)->with('flowbill')
        ->where($sideWhere)
        ->whereOr($whereOr)
        ->order($order)
        ->page($data['page'], $data['limit'])
        ->select();
      $count = $this->model->alias($data['alias'])
        ->hasWhere('flowbill', $hwhere)->with('flowbill')
        ->where($sideWhere)
        ->whereOr($whereOr)
        ->count();
    } else {
      $list = $this->model->hasWhere('flowbill', $hwhere)->with('flowbill')
        ->where($sideWhere)
        ->whereOr($whereOr)
        ->order($order)
        ->limit($data['begin'], $data['limit'])
        ->select();
      $count = $this->model->hasWhere('flowbill', $hwhere)->with('flowbill')
        ->where($sideWhere)
        ->whereOr($whereOr)
        ->count();
    }
    return [
      'list' => $list,
      'count' => $count
    ];
  }
  //--------------------------关联流程取列表（结束）----------------------------------------
  /**
   * 获取流程单据
   */
  public function getflow($id = 0)
  {
    return $this->model->with(['flowbill', 'glchaosong'])->where(['id' => $id])->find();
  }
  /**
   * 添加流程表单
   */
  public function addflow($data = [], $flowData = [])
  {
    $fbmodel = new \app\common\model\pmm\PmmFlowBill();
    $result = $fbmodel->create($flowData); //先主表
    if ($result) {
      $data['id'] = $result->id; //直接 副表ID=主表ID
      $res3 = $this->model->create($data); //新增 一定是 create.
      if ($res3) {
        $result = $this->model->with('flowbill')->where(['id' => $res3->id])->find();
        return $result;
      }
    }
    return [];
  }

  /**
   * 编辑流程表单
   */
  public function editflow($data = [], $flowData = [])
  {
    $tmodel = $this->model->find($data['id']);
    if ($tmodel) {
      if ($data['is_put'] == 3) { //撤回时，不改变其它数据
        $data = [
          'id' => $data['id']
        ];
      }
      $res = $tmodel->save($data);
      if ($res) {
        $flowData['id'] = $data['id']; //主表ID=副表ID
        $fbmodel = new \app\common\model\pmm\PmmFlowBill();
        $main = $fbmodel->find($data['id']);
        if ($main) {
          $main->save($flowData);
          return $this->model->with('flowbill')->where(['id' => $data['id']])->find();
        }
      }
    }
    return [];
  }

  /**
   * 提交流程
   */
  public function putflow($data = [], $flowData = [])
  {
    $flowData['id'] = $data['id'];
    $fbmodel = new \app\common\model\pmm\PmmFlowBill();
    $main = $fbmodel->find($data['id']);
    if ($main) {
      $main->save($flowData);
      return $this->model->with('flowbill')->where(['id' => $data['id']])->find();
    }
    return [];
  }
}
